/* components */
import { AuthTreeNode } from '@src/modules/account/roleModule/component/AuthTree/model'
import { AuthList } from '@src/modules/account/roleModule/component'
/* enum */
import ComponentNameEnum from '@model/enum/ComponentNameEnum'
import { RoleNameEnum } from '@model/biz/Role'
import EventNameEnum from '@model/enum/EventNameEnum'
/* hooks */
import { useStoreAuthGroups, useStoreFetchRoleDisPlayOrHidePhone, useStoreIsExportEncryption } from "@src/modules/account/roleModule/store/hooks"
import useLoading from '@src/modules/account/roleModule/hooks/useLoading'
import { useEventListener } from '@vueuse/core'
/* model */
import Role, { RoleAuthDepthEnum } from '@model/entity/Role/Role'
/* scss */
import '@src/modules/account/roleModule/component/RoleViewAuthView/index.scss'
/* vue */
import { ComponentInstance, computed, ComputedRef, defineComponent, nextTick, reactive, Ref, ref, toRefs, watch } from 'vue'
import { CreateElement } from 'vue'
/* util */
import { getDefaultCheckedKeys, getDefaultExpandedKeys, getWaterfallItemWidth } from '@src/modules/account/roleModule/component/RoleViewAuthView/util'
import { findComponentsDownward, findComponentDownward, findBrothersComponents } from '@src/util/assist'
import {t} from '@src/locales'

type CheckDataType = {
  checkedNodes: AuthTreeNode[];
  checkedKeys: string[];
  halfCheckedKeys: string[];
}

type RoleTreeRenderDataType = {
  data: AuthTreeNode;
}

export type RoleViewAuthViewProps = {
  disabled: boolean;
}

export interface RoleViewAuthViewSetupState {
  currentSelectRole: ComputedRef<Role>;
  getCheckedKeys: () => string[];
  outsideShow: VoidFunction;
  outsideHide: VoidFunction;
  outsideGetCheckedKeys: () => Promise<string[]>;
  outsideGetAuthTreeData: () => AuthTreeNode[];
}

export enum RoleViewAuthViewEventEnum {
  Input = 'input'
}

export type RoleViewAuthViewEmitsOptions = {
  input: () => void;
}

export type RoleViewAuthViewInstance = ComponentInstance & RoleViewAuthViewSetupState
export type RoleViewAuthViewVM = RoleViewAuthViewSetupState & RoleViewAuthViewProps & ComponentInstance

export default defineComponent({
  name: ComponentNameEnum.RoleViewAuthView,
  emits: [
    RoleViewAuthViewEventEnum.Input
  ],
  props: {
    disabled: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      checkedKeys: [] as string[],
    }
  },
  setup(props: RoleViewAuthViewProps, { slots, emit }) {
    
    const { authGroups } = useStoreAuthGroups()
    const { loading } = useLoading()
    const { isExportEncryption, setIsExportEncryption } = useStoreIsExportEncryption()
    const fetchRoleDisPlayOrHidePhone = useStoreFetchRoleDisPlayOrHidePhone()
    
    let waterfallItemWidth = ref(getWaterfallItemWidth())
    let waterfallIsFinishLoad = ref(false)
    
    
    let defaultCheckedKeys: Ref<string[]> = ref([])
    
    let isUseDefaultExpandedKeys = ref(false)
    
    const defaultExpandedKeys: ComputedRef<string[]> = computed(() => {
      return isUseDefaultExpandedKeys.value ? getDefaultExpandedKeys(authGroups.value) : []
    })
    
    let authTreeData = ref(
      AuthTreeNode.transformByAuthGroup(authGroups.value, props.disabled)
    )
    
    watch(
      authGroups, 
      (newValue) => {
        defaultCheckedKeys.value = getDefaultCheckedKeys(newValue)
        authTreeData.value = AuthTreeNode.transformByAuthGroup(authGroups.value, props.disabled)
      }, 
      {
        immediate: true
      }
    )
    
    function onCheckboxIsExportEncryptionInputHandler() {
      
      setIsExportEncryption(!isExportEncryption.value)
      
      fetchRoleDisPlayOrHidePhone()
      
    }
    
    function outsideGetAuthTreeData() {
      return authTreeData.value
    }
    
    function computedWaterfallItemWidth() {
      waterfallItemWidth.value = getWaterfallItemWidth()
    }
    
    function onWaterfallFinishLoadHandler() {
      waterfallIsFinishLoad.value = true
    }
    
    useEventListener(document, EventNameEnum.Resize, () => {
      computedWaterfallItemWidth()
    })
    
    return {
      authGroups,
      loading,
      authTreeData,
      defaultCheckedKeys,
      defaultExpandedKeys,
      isExportEncryption,
      waterfallItemWidth,
      waterfallIsFinishLoad,
      isUseDefaultExpandedKeys,
      outsideGetAuthTreeData,
      onCheckboxIsExportEncryptionInputHandler,
      onWaterfallFinishLoadHandler
    }
    
  },
  computed: {
    defaultCheckedKeysMap(): Record<string, string> {
      return (
        this.checkedKeys.reduce(
          (acc, current) => {
            acc[current] = current
            return acc
          }, 
          {} as Record<string, string>
        )
      )
    }
  },
  watch: {
    authGroups(newValue) {
      this.checkedKeys = this.getCheckedKeys()
    }
  },
  mounted() {
    this.checkedKeys = this.getCheckedKeys()
  },
  methods: {
    getCheckedKeys() {
      
      const elTreeNodeComponents = findComponentsDownward(this, 'ElTreeNode')
      
      let checkedKeys: string[] = []
      
      let elCheckboxComponent = null
      
      elTreeNodeComponents.forEach((elTreeNodeComponent: Record<string, any>) => {
        elCheckboxComponent = findComponentDownward(elTreeNodeComponent, 'ElCheckbox')
        
        if (elCheckboxComponent?.value && elTreeNodeComponent?.node?.data?.key) {
          checkedKeys.push(elTreeNodeComponent.node.data.key)
        }
        
      })
      
      return checkedKeys
    },
    onNodeCheckHandler() {
      setTimeout(() => {
        this.checkedKeys = this.getCheckedKeys()
      }, 300)
    },
    async outsideGetCheckedKeys() {
      return this.checkedKeys
    },
    outsideSetCheckedKeys() {
      this.checkedKeys = this.getCheckedKeys()
    },
    setElTreeDefaultExpanded() {
      
      const elTreeComponents = findComponentsDownward(this, 'ElTree')
      
      let elTreeNodeComponents: Record<string, any>[] = []
      
      elTreeComponents.forEach((elTreeComponent: Record<string, any>) => {
        
        const elTreeNodeComponent = findComponentDownward(elTreeComponent, 'ElTreeNode')
        
        const brothersComponents = findBrothersComponents(elTreeNodeComponent, 'ElTreeNode').concat([elTreeNodeComponent])
        
        elTreeNodeComponents = elTreeNodeComponents.concat(brothersComponents)
        
      })
      
      elTreeNodeComponents.forEach(component => {
        component.handleExpandIconClick()
      })
      
    },
    renderExportEncrypt(h: CreateElement, data: RoleTreeRenderDataType) {
      
      if (data.data.key !== RoleNameEnum.EXPORT_IN) {
        return null
      }
      
      const isImportExportCheckboxChecked = (
        Boolean(this.defaultCheckedKeysMap[RoleNameEnum.SYSTEM])
        || Boolean(this.defaultCheckedKeysMap[RoleNameEnum.EXPORT_IN])
      )
      
      const disabled = this.disabled || !isImportExportCheckboxChecked
      
      const label = t('account.roleModule.exportEncryption')
      
      return (
        <el-checkbox
          key={label}
          label={label}
          disabled={disabled}
          value={this.isExportEncryption}
          onInput={this.onCheckboxIsExportEncryptionInputHandler}
        >
          { label }
        </el-checkbox>
      )
      
    },
    renderContent(h: CreateElement, data: RoleTreeRenderDataType) {
      
      const node = data.data
      const isLastLevel = node?.level == AuthTreeNode.lastLevel
      
      const isUserRadio = node?.aLevel != 2
      const isTagRadio = node?.aLevel == 2 || node?.aLevel == 3
      
      const isSelected = Boolean(this.defaultCheckedKeysMap[node?.key])
      
      const disabled = this.disabled
      
      const isShowRadio = node?.isShowRadio && isLastLevel
      
      const onRadioChangeHandler = (value: string | number) => {
        node.depth = value as RoleAuthDepthEnum
      }
      
      const name = (
        <div class="role-auth-view-tree-row__name">
          { node?.name || '' }
        </div>
      )
      
      const radio = (
        <div class="role-auth-view-tree-row__radio" onClick={(event: Event) => {
          event.stopPropagation()
        }}>
          <el-radio-group disabled={disabled} value={node.depth} onInput={onRadioChangeHandler}>
            
            <el-radio label={RoleAuthDepthEnum.All}>
              {t('common.base.all')}
            </el-radio>
            
            {isTagRadio && (
              <el-radio label={RoleAuthDepthEnum.Dept}>
                {t('common.base.department')}
              </el-radio>
            )}
            
            {isUserRadio && (
              <el-radio label={RoleAuthDepthEnum.Person}>
                {t('common.base.personal')}
              </el-radio>
            )}
            
          </el-radio-group>
        </div>
      )
      
      const exportEncrypt = this.renderExportEncrypt(h, data)
      
      if (exportEncrypt) {
        return (
          <div class="role-auth-view-tree-row">
            <div class="role-auth-view-tree-row__export">
              { name }
              { exportEncrypt }
            </div>
            { isShowRadio && radio }
          </div>
        )
      }
      
      return (
        <div class="role-auth-view-tree-row">
          { name }
          { isShowRadio && radio }
        </div>
      )
    }
  },
  render() {
    
    const classNames = [
      ComponentNameEnum.RoleViewAuthView,
      this.waterfallIsFinishLoad ? 'role-view-auth-view-finish' : ''
    ]
    
    return (
      <div class={classNames}>
        <AuthList data={this.authTreeData} disabled={this.disabled} />
      </div>
    ) as any
  }
}) as any
